package br.com.betioli.jme.games.sokobob.level;

import br.com.betioli.jme.games.sokobob.config.GameConfig;
import java.io.IOException;
import java.io.InputStream;

/**
 * Classe responsável por carregar e decodificar os arquivos externos level.x
 * 
 * @author Alexandre Parra Betioli
 */
public abstract class LevelFactory {

    private static char[][] map;
    private static int numberOfBones;
    private static InputStream is;
    private static Level level;

    /** 
     * Retorna o level carregado atualmente ou null caso nenhum esteja carregado
     */ 
    public static Level getLevel() {
        return level;
    }

    /**
     * Realiza o carregamento do level a partir do arquivo level.x onde x é o 
     * levelIndex. Retorna true caso exista, e false caso contrário.
     */
    public static boolean load(int levelIndex) {

        if (levelIndex <= 0) {
            levelIndex = 0;
        }
        
        if (! hasLevel(levelIndex) ) {
            return false; //THE END        
        }
        
        try {
            readBoard(is);
            level = new Level(levelIndex, map, numberOfBones);

        } catch (IOException ex) {
            return false;

        } finally {
            try {
                is.close();
                is = null;
            } catch (Exception e) {}
        }

        return true;
    }

    /**
     * Abre stream do arquivo de nível
     */
    private static boolean hasLevel(int level) {
        is = LevelFactory.class.getResourceAsStream( "/res/levels/level." + level);
        return is != null;
    }    
    
    /**
     * Carrega um mapa a partir do arquivo
     */
    private static void readBoard(InputStream is) throws IOException {

        //Inicializar
        
        numberOfBones = 0;
        
        map = new char[GameConfig.COLUMNS][GameConfig.ROWS];

        for (int r = 0; r < GameConfig.ROWS; r++) {
            for (int c = 0; c < GameConfig.COLUMNS; c++) {
                map[c][r] = GameConfig.GRASS_REF;
            }
        }        
        
        //Preencher
        
        for (byte r = 0; r < GameConfig.ROWS; r++) {

            int item = '\n';

            for (byte c = 0; c < GameConfig.COLUMNS;) {

                item = is.read(); //Lê o proximo byte do stream e retorna como int

                switch (item) {
                    case -1:
                        return;

                    case GameConfig.GRASS_REF:
                        map[c++][r] = GameConfig.GRASS_REF;
                        break;
                        
                    case GameConfig.WALL_REF:
                        map[c++][r] = GameConfig.WALL_REF;
                        break;                        

                    case GameConfig.TARGET_REF:
                        map[c++][r] = GameConfig.TARGET_REF;
                        break;                        
                        
                    case GameConfig.BONE_REF:
                        map[c++][r] = GameConfig.BONE_REF;
                        numberOfBones++;
                        break;

                    case GameConfig.BOX_IN_TARGET_REF:
                        map[c++][r] = GameConfig.BOX_IN_TARGET_REF;
                        numberOfBones++;
                        break;                                  
                        
                    case GameConfig.BOB_REF:
                        map[c++][r] = GameConfig.BOB_REF;
                        break;
                        
                    case GameConfig.BOB_IN_TARGET_REF:
                        map[c++][r] = GameConfig.BOB_IN_TARGET_REF;
                        break;                                  

                    case GameConfig.FLOWERS_REF:
                        map[c++][r] = GameConfig.FLOWERS_REF;
                        break;

                    case '\n': //Caso quebra de linha antes do limite de colunas, completa com grama
                        while (c < GameConfig.COLUMNS) {
                            map[c++][r] = GameConfig.GRASS_REF;
                        }
                        continue;
                        
                    default:
                        continue;
                }
            }

            //Decarta o que houver após o limite de colunas na mesma linha
            while (item != '\n') {
                item = is.read();
            }
        }
    }
}
